package com.allwees.bs.c.module.product.service.impl;

import com.allwees.bs.c.module.order.repository.OrderItemRepository;
import com.allwees.bs.c.module.product.dao.ProductDao;
import com.allwees.bs.c.module.product.dao.SkuDao;
import com.allwees.bs.c.module.product.dto.MarketingInfo;
import com.allwees.bs.c.module.product.dto.ProductDetailsDTO;
import com.allwees.bs.c.module.product.dto.ProductReviewDTO;
import com.allwees.bs.c.module.product.dto.SkuCheckDTO;
import com.allwees.bs.c.module.product.dto.SkuCheckResult;
import com.allwees.bs.c.module.product.dto.SkuDTO;
import com.allwees.bs.c.module.product.entity.ProductEntity;
import com.allwees.bs.c.module.product.entity.SkuEntity;
import com.allwees.bs.c.module.product.init.BanWordsHelper;
import com.allwees.bs.c.module.product.mapper.ProductMapper;
import com.allwees.bs.c.module.product.repository.CategoryRepository;
import com.allwees.bs.c.module.product.repository.ProductRepository;
import com.allwees.bs.c.module.product.service.ProductService;
import com.allwees.bs.c.module.user.repository.ProductCollectionRepository;
import com.allwees.bs.core.modelbase.constant.ResultEnum;
import com.allwees.bs.core.modelbase.exception.BusinessException;
import com.allwees.bs.core.modelbase.page.PageParams;
import com.allwees.bs.core.modelbase.page.PaginateDTO;
import com.allwees.support.marketing.handler.PriceAdjustor;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
@Lazy(false)
public class ProductServiceImpl extends ServiceImpl<ProductDao, ProductEntity> implements ProductService {

    @Autowired
    private ProductRepository productRepository;

    @Resource
    private SkuDao skuDao;

    @Resource
    private ProductDao productDao;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ProductCollectionRepository collectionRepository;

    @Autowired
    private OrderItemRepository orderItemRepository;

    @Autowired
    private CategoryRepository categoryRepository;

//    @Autowired
//    private ProductReviewEsRepository productReviewEsRepository;

    @Autowired
    private BanWordsHelper banWordsHelper;

    @Override
    public ProductDetailsDTO findProductByUuid(String productUuid) {
        ProductEntity productEntity = productRepository.getByUuid(productUuid);
        return new ProductDetailsDTO(productEntity);
    }

    @Override
    public SkuDTO findSkuByUuid(String skuUuid) {
        SkuEntity sku = skuDao.findByUuid(skuUuid);
        return new SkuDTO(sku);
    }

    /**
     * 1.MQ刷新缓存
     * 2.controller搜索
     * 首页搜索商品
     */
    @Override
    public PaginateDTO<ProductDetailsDTO> search(String keyword, PageParams pageParams) {
        log.info("===>user search product from database.keyword:{},pageSize:{},pageNum:{}", keyword, pageParams.getSize(), pageParams.getCurrent());
        if (banWordsHelper.contains(keyword)) { //包含禁用词
            return PaginateDTO.of(0, 0, pageParams);
        }
        return doSearch(keyword, pageParams);
    }

    @Override
    public PaginateDTO<ProductDetailsDTO> search4RefreshTask(String keywords, PageParams pageParams) {
        log.info("===>task search product from database.keywords:{},pageSize:{},pageNum:{}", keywords, pageParams.getSize(), pageParams.getCurrent());
        return doSearch(keywords, pageParams);
    }

    private PaginateDTO<ProductDetailsDTO> doSearch(String keywords, PageParams pageParams) {
        Page<ProductEntity> page = this.productRepository.search(keywords, pageParams.toPageable());
        PaginateDTO<ProductDetailsDTO> products = PaginateDTO.of(page.getTotalElements(), page.getContent().size(), pageParams);
        List<ProductDetailsDTO> pds = new ArrayList<>();
        page.getContent().forEach(entity -> {
            entity.setPhotosStr(null);
            entity.setDescription(null);
            ProductDetailsDTO product = new ProductDetailsDTO(entity);
            pds.add(product);
        });
        products.setResults(pds);
        return products;
    }

    /**
     * 获取商品详情
     */
    @Override
    public ProductDetailsDTO getProductDetails(String productUuid) {
        ProductEntity productEntity = this.productRepository.getByUuid(productUuid);
        if (productEntity == null) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }

        //获取商品的SKU列表
        List<SkuEntity> skuEntities = this.skuDao.findProductAllSku(productUuid);
        return this.productMapper.entity2DTO(productEntity, skuEntities);
    }


    @Override
    public List<ProductDetailsDTO> getRelatedProducts(String productUuid, int size) {
        ProductEntity productEntity = this.productRepository.getByUuid(productUuid);
        if (Objects.isNull(productEntity)) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }
        String key = productEntity.getCategoryNo();
        List<ProductEntity> products = productRepository.findRelatedProducts(key, size);
        return products.stream().map(ProductDetailsDTO::new).collect(Collectors.toList());
    }

    /**
     * 获取某个分类的商品
     *
     * @param categoryNo 商品分类
     * @param pageParams 翻页参数
     * @return 翻页商品列表对象
     */
    @Override
    public PaginateDTO<ProductDetailsDTO> getCategoryProducts(String categoryNo, PageParams pageParams) {
        log.info("===>user load category product from database.categoryNo:{},pageSize:{},pageNum:{}", categoryNo, pageParams.getSize(), pageParams.getCurrent());
        return doQueryCategoryProduct(categoryNo, pageParams);
    }

    @Override
    public PaginateDTO<ProductDetailsDTO> queryCategoryProduct4RefreshTask(String categoryNo, PageParams pageParams) {
        log.info("===>task load category product from database.categoryNo:{},pageSize:{},pageNum:{}", categoryNo, pageParams.getSize(), pageParams.getCurrent());
        return doQueryCategoryProduct(categoryNo, pageParams);
    }

    private PaginateDTO<ProductDetailsDTO> doQueryCategoryProduct(String categoryNo, PageParams pageParams) {
        Page<ProductEntity> productEntityPage;
        // 查询该商品分类的子分类（如果有），然后获取包括自身及所有子分类的商品
        if (categoryNo != null) {
            productEntityPage = this.productRepository.findCategoryProducts(_getAllCategoryNos(categoryNo), pageParams.toPageable());
        } else {
            productEntityPage = this.productRepository.findPageAll(pageParams.toPageable(Sort.Direction.DESC, "createdAt"));
        }
        return assembleProduct(productEntityPage.getTotalElements(), productEntityPage.getContent(), pageParams);
    }

    private List<String> _getAllCategoryNos(String categoryNo) {
        List<String> allCatNos = new ArrayList<>();
        allCatNos.add(categoryNo);
        List<String> categoryNos = this.categoryRepository.findChildCategoryNos(categoryNo);
        if (categoryNos != null && !categoryNos.isEmpty()) {
            allCatNos.addAll(categoryNos);
        }
        return allCatNos;
    }

    @Override
    public ProductReviewDTO getProductReviews(String productUuid, int current) {
        ProductReviewDTO reviewDto = new ProductReviewDTO();

        ProductEntity product = productRepository.getByUuid(productUuid);
        if (product == null || StringUtils.isBlank(product.getNo())) {
            return reviewDto;
        }

        reviewDto.setTotal(product.getTotalReviews());
//        List<EsProductReview> reviews = productReviewEsRepository.searchByNoAndPageNo(product.getNo(), current);
//        if (CollectionUtils.isEmpty(reviews)) {
//            return reviewDto;
//        }
//        for (EsProductReview review : reviews) {
//            review.getReviews().forEach(reviewDto::add);
//        }
        return reviewDto;
    }

    @Override
    public List<ProductDetailsDTO> collectedOrBought(List<ProductDetailsDTO> products, String userUuid) {
        if (CollectionUtils.isEmpty(products) || StringUtils.isBlank(userUuid)) {
            return products;
        }
        Set<String> productUuids = products.stream().map(ProductDetailsDTO::getUuid).collect(Collectors.toSet());

        Set<String> collProductUuids = collectionRepository.findCollProductUuids(userUuid, productUuids);
        Set<String> buyedProductUuids = orderItemRepository.findByUserAndProduct(userUuid, productUuids);

        products.forEach(product -> {
            product.setUserIsCollection(collProductUuids.contains(product.getUuid()));
            product.setUserIsOrder(buyedProductUuids.contains(product.getUuid()));
        });

        return products;
    }

    /**
     * 组装商品，获取商品的拼团信息，用户是否关注等信息
     *
     * @param pageParams 翻页信息
     * @return 组装完成的商品翻页对象
     */
    private PaginateDTO<ProductDetailsDTO> assembleProduct(long total, List<ProductEntity> data, PageParams pageParams) {
        PaginateDTO<ProductDetailsDTO> page = PaginateDTO.of(total, data.size(), pageParams);
        if (CollectionUtils.isEmpty(data)) {
            return page;
        }
        page.setResults(data.stream().map(ProductDetailsDTO::new).collect(Collectors.toList()));
        return page;
    }

    @Override
    public PaginateDTO<ProductDetailsDTO> findMarketingProducts(int marketingType, PageParams pageParams) {
        QueryWrapper<ProductEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 0);
        wrapper.eq("marketing_type & " + marketingType, marketingType);
        wrapper.orderByDesc("score");
        return query(wrapper, pageParams);
    }

    @Override
    public PaginateDTO<ProductDetailsDTO> flashProducts(PageParams pageParams, int marketingDay) {
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<ProductEntity> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageParams.getCurrent(), pageParams.getSize());
        page = baseMapper.queryPage(page, marketingDay);
        return assembleProduct(page.getTotal(), page.getRecords(), pageParams);
    }

    @Override
    public PaginateDTO<ProductDetailsDTO> below5Products(PageParams pageParams) {
        QueryWrapper<ProductEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 0);
        wrapper.lt("retail_price", PriceAdjustor.getRetailPrice(new BigDecimal(5)));
        wrapper.orderByDesc("score");
        return query(wrapper, pageParams);
    }

    private PaginateDTO<ProductDetailsDTO> query(QueryWrapper<ProductEntity> wrapper, PageParams pageParams) {
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<ProductEntity> page =
                new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageParams.getCurrent(), pageParams.getSize());
        page = super.page(page, wrapper);
        return assembleProduct(page.getTotal(), page.getRecords(), pageParams);
    }

    @Override
    public List<ProductEntity> freeGiftsInOnesCart(String userUuid) {
        return baseMapper.freeGiftsInOnesCart(userUuid);
    }

    @Override
    public MarketingInfo getMarketingInfo(String productUuid) {
        ProductEntity product = baseMapper.findByUuid(productUuid);
        if (product == null) {
            return null;
        }
        return new MarketingInfo(product);
    }

    @Override
    public SkuCheckResult checkSku(List<SkuCheckDTO> skus) {
        if (CollectionUtils.isEmpty(skus)) {
            return SkuCheckResult.success();
        }
        List<SkuEntity> list = skuDao.selectForCheck(skus.stream().map(SkuCheckDTO::getSkuUuid).collect(Collectors.toList()));
        Assert.isTrue(skus.size() == list.size(), "Contains Invalid Sku~");
        Map<String, SkuCheckDTO> map = skus.stream().collect(Collectors.toMap(SkuCheckDTO::getSkuUuid, e -> e));
        for (SkuEntity sku : list) {
            sku.setBuyQuantity(map.get(sku.getUuid()).getNum());
        }
        return SkuCheckResult.of(list);
    }

    @Override
    public SkuDTO addInventory(String skuUuid, int addend) {
        skuDao.updateInventory(skuUuid, addend);
        //SkuEntity skuEntity = skuDao.findByUuid(skuUuid);
        SkuEntity skuEntity = skuDao.selectBySkuUuid(skuUuid);
        return new SkuDTO(skuEntity);
    }

    @Override
    public SkuDTO decInventory(String skuUuid, int minus) {
        if (skuDao.updateInventory(skuUuid, -minus) > 0) {
            //SkuEntity skuEntity = skuDao.findByUuid(skuUuid);
            SkuEntity skuEntity = skuDao.selectBySkuUuid(skuUuid);
            productDao.addTotalSales(skuEntity.getProductUuid(), minus);
            return new SkuDTO(skuEntity);
        }
        return null;

    }
}
